#include "../h+cell/manip.hpp"
#include "../h+cell/cell.hpp"

#include "yocto/string/vfs-utils.hpp"
#include "yocto/exception.hpp"

using namespace yocto;

int main( int argc, char *argv[] )
{
    const char *progname = _vfs:: get_base_name(argv[0]);
    try
    {
        
        ////////////////////////////////////////////////////////////////////////
        //
        // check arguments
        //
        ////////////////////////////////////////////////////////////////////////
        if( argc < 3 )
            throw exception("usage: %s config.lua input_file", progname );
        const string config_file( argv[1] );
        const string input_file(  argv[2] );
        
        //const string output_file(argv[3]);
        
        ////////////////////////////////////////////////////////////////////////
        //
        // create data
        //
        ////////////////////////////////////////////////////////////////////////
        Cell  cell(config_file);
        Manip manip(input_file);
        
        
        std::cerr << "cell.sol: @pH=" << cell.sol.pH() << std::endl;
        std::cerr << cell.sol << std::endl;
        
        std::cerr << "cell.out: @pH=" << cell.outside(0).pH() << std::endl;
        std::cerr << cell.outside(0) << std::endl;
        
        ////////////////////////////////////////////////////////////////////////
        //
        // recompute initial pH from data
        //
        ////////////////////////////////////////////////////////////////////////
        {
            const double h0  = manip.h[1];
            initializer &ini = cell.InitIn;
            bool could_change = false;
            for( size_t i=1; i <= ini.size(); ++i )
            {
                constraint &cst = ini[i];
                if( 1 == cst.size() && cst.has("H+") )
                {
                    double &w = *cst.weight_address_of("H+");
                    std::cerr << "Changing Initializer Internal pH to " << manip.pH[1] << std::endl;
                    cst.set_value( h0 * w );
                    could_change = true;
                    break;
                }
            }
            if( !could_change )
                throw exception("couldn't change pH");
            
            cell.ReloadInside();
            std::cerr << "cell.sol: @pH=" << cell.sol.pH() << std::endl;
            std::cerr << cell.sol << std::endl;
        }
        
        ////////////////////////////////////////////////////////////////////////
        //
        // compute steady and/or set steady
        //
        ////////////////////////////////////////////////////////////////////////
        std::cerr << "ComputeSteadyEm" << std::endl;
        cell.ComputeSteadyEm();
        
        {
            lua_State *L = cell();
            lua_settop(L, 0);
            lua_getglobal(L, "Em");
            if( lua_isnumber(L, -1) )
            {
                const double Eini = lua_tonumber(L, -1);
                std::cerr << "Detect user's Em=" << Eini << std::endl;
                cell.EnforceSteadyEm( Eini );
                cell.RescaleEffectors();
            }
        }

        ////////////////////////////////////////////////////////////////////////
        //
        // rescale rates (doesn't change stationary)
        // if "rescale_rates" is found
        //
        ////////////////////////////////////////////////////////////////////////
        cell.TryRescaleAllRates();
        
        
        
    }
    catch( const exception &e )
    {
        std::cerr << e.what() << std::endl;
        std::cerr << e.when() << std::endl;
        return -1;
    }
    catch(...)
    {
        std::cerr << "Unhandled exception in " << progname << std::endl;
        return -1;
    }
    
    return 0;
}